<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import PrizeList from "./PrizeList.vue";
import { useElementStyle, useElementPosition } from "@/hooks/useElement";
import StarsBackground from "@/components/StarsBackground/index.vue";
import confetti from "canvas-confetti";
import { filterData, selectCard } from "@/utils";
import { rgba } from "@/utils/color";
import { IPersonConfig } from "@/types/storeType";
import { Scene, PerspectiveCamera, Object3D, Vector3 } from "three";
import { CSS3DRenderer, CSS3DObject } from "three-css3d";
import { TrackballControls } from "three/examples/jsm/controls/TrackballControls.js";
import * as TWEEN from "@tweenjs/tween.js";
import useStore from "@/store";
import { storeToRefs } from "pinia";
import { useRouter } from "vue-router";
import { useToast } from "vue-toast-notification";
import "vue-toast-notification/dist/theme-sugar.css";

const isLoading = ref(false);
const toast = useToast();
const router = useRouter();
const personConfig = useStore().personConfig;
const globalConfig = useStore().globalConfig;
const prizeConfig = useStore().prizeConfig;

const { getAllPersonList: allPersonList } = storeToRefs(personConfig);
const { getCurrentPrize: currentPrize } = storeToRefs(prizeConfig);
const {
  getTopTitle: topTitle,
  getCardColor: cardColor,
  getPatterColor: patternColor,
  getPatternList: patternList,
  getTextColor: textColor,
  getLuckyColor: luckyColor,
  getCardSize: cardSize,
  getTextSize: textSize,
  getRowCount: rowCount,
} = storeToRefs(globalConfig);

const tableData = ref<any[]>([]);
const currentStatus = ref(0); // 0:初始 1:准备 2:抽奖中 3:结束
const ballRotationY = ref(0);
const containerRef = ref<HTMLElement>();
const canOperate = ref(true);
const cameraZ = ref(3000);

const scene = ref<Scene>();
const camera = ref<PerspectiveCamera>();
const renderer = ref<CSS3DRenderer>();
const controls = ref<TrackballControls>();
const objects = ref<CSS3DObject[]>([]);

const targets = {
  grid: <any[]>[],
  helix: <any[]>[],
  table: <any[]>[],
  sphere: <any[]>[],
};

const luckyTargets = ref<IPersonConfig[]>([]);
const luckyCardList = ref<number[]>([]);
const luckyCount = ref(3); // 固定每次抽3人
const personPool = ref<IPersonConfig[]>([]);

const intervalTimer = ref<any>(null);

// 初始化数据，填满表格
function initTableData() {
  if (allPersonList.value.length <= 0) return;
  const totalCount = rowCount.value * 7;
  const orginPersonData = JSON.parse(JSON.stringify(allPersonList.value)); // 使用当前人员数据
  const orginPersonLength = orginPersonData.length;

  if (orginPersonLength < totalCount) {
    const repeatCount = Math.ceil(totalCount / orginPersonLength);
    for (let i = 0; i < repeatCount; i++) {
      tableData.value = tableData.value.concat(
        JSON.parse(JSON.stringify(orginPersonData))
      );
    }
  } else {
    tableData.value = orginPersonData.slice(0, totalCount);
  }
  tableData.value = filterData(
    tableData.value.slice(0, totalCount),
    rowCount.value
  );
}

// 初始化3D场景
const init = () => {
  // 清理之前的场景
  if (scene.value) {
    objects.value.forEach((obj) => scene.value!.remove(obj));
    objects.value = [];
  }
  if (renderer.value && containerRef.value) {
    containerRef.value.removeChild(renderer.value.domElement);
  }

  const felidView = 40;
  const width = window.innerWidth;
  const height = window.innerHeight;
  const aspect = width / height;
  const nearPlane = 1;
  const farPlane = 10000;
  const WebGLoutput = containerRef.value;

  scene.value = new Scene();
  camera.value = new PerspectiveCamera(felidView, aspect, nearPlane, farPlane);
  camera.value.position.z = cameraZ.value;
  renderer.value = new CSS3DRenderer();
  renderer.value.setSize(width, height * 0.9);
  renderer.value.domElement.style.position = "absolute";
  renderer.value.domElement.style.paddingTop = "50px";
  renderer.value.domElement.style.top = "50%";
  renderer.value.domElement.style.left = "50%";
  renderer.value.domElement.style.transform = "translate(-50%, -50%)";
  WebGLoutput!.appendChild(renderer.value.domElement);

  controls.value = new TrackballControls(
    camera.value,
    renderer.value.domElement
  );
  controls.value.rotateSpeed = 1;
  controls.value.staticMoving = true;
  controls.value.minDistance = 500;
  controls.value.maxDistance = 6000;
  controls.value.addEventListener("change", render);

  const tableLen = tableData.value.length;
  for (let i = 0; i < tableLen; i++) {
    let element = document.createElement("div");
    element.className = "element-card";

    const number = document.createElement("div");
    number.className = "card-id";
    number.textContent = tableData.value[i].uid;
    element.appendChild(number);

    const symbol = document.createElement("div");
    symbol.className = "card-name";
    symbol.textContent = tableData.value[i].name;
    element.appendChild(symbol);

    const detail = document.createElement("div");
    detail.className = "card-detail";
    detail.innerHTML = `${tableData.value[i].department}<br/>${tableData.value[i].identity}`;
    element.appendChild(detail);

    element = useElementStyle(
      element,
      tableData.value[i],
      i,
      patternList.value,
      patternColor.value,
      cardColor.value,
      cardSize.value,
      textSize.value
    );
    const object = new CSS3DObject(element);
    object.position.x = Math.random() * 4000 - 2000;
    object.position.y = Math.random() * 4000 - 2000;
    object.position.z = Math.random() * 4000 - 2000;
    scene.value.add(object);

    objects.value.push(object);
  }

  createTableVertices();
  createSphereVertices();
  createHelixVertices();

  function createTableVertices() {
    targets.table = []; // 清空之前的目标数据
    const tableLen = tableData.value.length;
    for (let i = 0; i < tableLen; i++) {
      const object = new Object3D();
      object.position.x =
        tableData.value[i].x * (cardSize.value.width + 40) -
        rowCount.value * 90;
      object.position.y =
        -tableData.value[i].y * (cardSize.value.height + 20) + 1000;
      object.position.z = 0;
      targets.table.push(object);
    }
  }

  function createSphereVertices() {
    targets.sphere = []; // 清空之前的目标数据
    let i = 0;
    const objLength = objects.value.length;
    const vector = new Vector3();
    for (; i < objLength; ++i) {
      let phi = Math.acos(-1 + (2 * i) / objLength);
      let theta = Math.sqrt(objLength * Math.PI) * phi;
      const object = new Object3D();
      object.position.x = 800 * Math.cos(theta) * Math.sin(phi);
      object.position.y = 800 * Math.sin(theta) * Math.sin(phi);
      object.position.z = -800 * Math.cos(phi);
      vector.copy(object.position).multiplyScalar(2);
      object.lookAt(vector);
      targets.sphere.push(object);
    }
  }

  function createHelixVertices() {
    targets.helix = []; // 清空之前的目标数据
    let i = 0;
    const vector = new Vector3();
    const objLength = objects.value.length;
    for (; i < objLength; ++i) {
      let phi = i * 0.213 + Math.PI;
      const object = new Object3D();
      object.position.x = 800 * Math.sin(phi);
      object.position.y = -(i * 8) + 450;
      object.position.z = 800 * Math.cos(phi + Math.PI);
      object.scale.set(1.1, 1.1, 1.1);
      vector.x = object.position.x * 2;
      vector.y = object.position.y;
      vector.z = object.position.z * 2;
      object.lookAt(vector);
      targets.helix.push(object);
    }
  }

  // 移除旧的 resize 监听，避免重复绑定
  window.removeEventListener("resize", onWindowResize);
  window.addEventListener("resize", onWindowResize, false);
  transform(targets.table, 1000);
  render();
};

// 重置为默认数据并重新初始化（核心修改）
const setDefaultPersonList = () => {
  personConfig.setDefaultPersonList(); // 设置默认数据
  initTableData(); // 重新初始化表格数据
  init(); // 重新初始化3D场景
};
const transform = (targets: any[], duration: number) => {
  TWEEN.removeAll();
  if (intervalTimer.value) {
    clearInterval(intervalTimer.value);
    intervalTimer.value = null;
    randomBallData("sphere");
  }

  return new Promise((resolve) => {
    const objLength = objects.value.length;
    for (let i = 0; i < objLength; ++i) {
      let object = objects.value[i];
      let target = targets[i];
      new TWEEN.Tween(object.position)
        .to(
          { x: target.position.x, y: target.position.y, z: target.position.z },
          Math.random() * duration + duration
        )
        .easing(TWEEN.Easing.Exponential.InOut)
        .start();

      new TWEEN.Tween(object.rotation)
        .to(
          { x: target.rotation.x, y: target.rotation.y, z: target.rotation.z },
          Math.random() * duration + duration
        )
        .easing(TWEEN.Easing.Exponential.InOut)
        .start()
        .onComplete(() => {
          // 1. 修复：遍历 luckyCardList 时，使用当前卡片索引 cardIndex，而非外层循环的 i
          if (luckyCardList.value.length) {
            luckyCardList.value.forEach((cardIndex: number) => {
              const item = objects.value[cardIndex];
              useElementStyle(
                item.element,
                {} as any,
                cardIndex, // 关键修复：将 i 改为 cardIndex
                patternList.value,
                patternColor.value,
                cardColor.value,
                cardSize.value,
                textSize.value,
                "sphere"
              );
            });
          }

          // 2. 重置抽奖状态
          luckyTargets.value = [];
          luckyCardList.value = [];
          canOperate.value = true;
        });
    }

    new TWEEN.Tween({})
      .to({}, duration * 2)
      .onUpdate(render)
      .start()
      .onComplete(() => {
        canOperate.value = true;
        resolve("");
      });
  });
};

function onWindowResize() {
  if (!camera.value || !renderer.value) return;
  camera.value.aspect = window.innerWidth / window.innerHeight;
  camera.value.updateProjectionMatrix();
  renderer.value.setSize(window.innerWidth, window.innerHeight);
  render();
}

function animation() {
  TWEEN.update();
  controls.value?.update();
  requestAnimationFrame(animation);
}

function rollBall(rotateY: number, duration: number) {
  TWEEN.removeAll();
  return new Promise((resolve) => {
    if (!scene.value) return resolve("");
    scene.value.rotation.y = 0;
    ballRotationY.value = Math.PI * rotateY * 1000;
    const rotateObj = new TWEEN.Tween(scene.value.rotation);
    rotateObj
      .to(
        {
          x: 0,
          y: ballRotationY.value,
          z: 0,
        },
        duration * 1000
      )
      .onUpdate(render)
      .start()
      .onComplete(() => resolve(""));
  });
}

function resetCamera() {
  if (!camera.value) return;
  new TWEEN.Tween(camera.value.position)
    .to(
      {
        x: 0,
        y: 0,
        z: 3000,
      },
      1000
    )
    .onUpdate(render)
    .start()
    .onComplete(() => {
      if (!camera.value) return;
      new TWEEN.Tween(camera.value.rotation)
        .to(
          {
            x: 0,
            y: 0,
            z: 0,
          },
          1000
        )
        .onUpdate(render)
        .start()
        .onComplete(() => {
          canOperate.value = true;
          camera.value.position.set(0, 0, 3000);
          camera.value.rotation.set(0, 0, 0);
          controls.value?.reset();
        });
    });
}

function render() {
  if (renderer.value && scene.value && camera.value) {
    renderer.value.render(scene.value, camera.value);
  }
}

// 进入抽奖（自动使用默认数据）
const enterLottery = async () => {
  if (!canOperate.value) return;
  setDefaultPersonList(); // 关键：进入抽奖时使用默认数据
  if (!intervalTimer.value) {
    randomBallData();
  }
  if (patternList.value.length) {
    for (let i = 0; i < patternList.value.length; i++) {
      if (i < rowCount.value * 7) {
        objects.value[patternList.value[i] - 1].element.style.backgroundColor =
          rgba(cardColor.value, Math.random() * 0.5 + 0.25);
      }
    }
  }
  canOperate.value = false;
  await transform(targets.sphere, 1000);
  currentStatus.value = 1;
  rollBall(0.1, 2000);
};

// 开始抽奖（自动使用默认数据）
const startLottery = () => {
  isLoading.value = true;
  if (!canOperate.value) return;
  // 验证是否有足够人员
  if (allPersonList.value.length < luckyCount.value) {
    toast.open({
      message: `至少需要${luckyCount.value}名人员参与`,
      type: "warning",
      position: "top-right",
      duration: 3000,
    });
    isLoading.value = false;
    return;
  }

  // 从默认人员中随机选择（已通过enterLottery确保是默认数据）
  personPool.value = JSON.parse(JSON.stringify(allPersonList.value));
  luckyTargets.value = [];
  for (let i = 0; i < luckyCount.value; i++) {
    if (personPool.value.length <= 0) break;
    const randomIndex = Math.floor(Math.random() * personPool.value.length);
    luckyTargets.value.push(personPool.value[randomIndex]);
  }

  toast.open({
    message: `正在抽取 ${luckyCount.value} 道美味菜品...`,
    type: "default",
    position: "top-right",
    duration: 3000,
  });
  currentStatus.value = 2;
  isLoading.value = false;
  rollBall(10, 3000);
};

const stopLottery = async () => {
  if (!canOperate.value) return;
  clearInterval(intervalTimer.value);
  intervalTimer.value = null;
  canOperate.value = false;
  await rollBall(0, 1);

  const windowSize = { width: window.innerWidth, height: window.innerHeight };
  luckyTargets.value.forEach((person: IPersonConfig, index: number) => {
    let cardIndex = selectCard(
      luckyCardList.value,
      tableData.value.length,
      person.id
    );
    luckyCardList.value.push(cardIndex);
    let item = objects.value[cardIndex];
    const { xTable, yTable } = useElementPosition(
      item,
      rowCount.value,
      { width: cardSize.value.width * 2, height: cardSize.value.height * 2 },
      windowSize,
      index
    );

    new TWEEN.Tween(item.position)
      .to({ x: xTable, y: yTable, z: 1000 }, 1200)
      .easing(TWEEN.Easing.Exponential.InOut)
      .onStart(() => {
        item.element = useElementStyle(
          item.element,
          person,
          cardIndex,
          patternList.value,
          patternColor.value,
          luckyColor.value,
          {
            width: cardSize.value.width * 2,
            height: cardSize.value.height * 2,
          },
          textSize.value * 2,
          "lucky"
        );
      })
      .start()
      .onComplete(() => {
        canOperate.value = true;
        currentStatus.value = 3;
      });

    new TWEEN.Tween(item.rotation)
      .to({ x: 0, y: 0, z: 0 }, 900)
      .easing(TWEEN.Easing.Exponential.InOut)
      .start()
      .onComplete(() => {
        confettiFire();
        resetCamera();
      });
  });
};

// 继续抽奖（自动使用默认数据）
const continueLottery = async () => {
  if (!canOperate.value) return;
  // 清除上一轮中奖标记并重置为默认数据
  setDefaultPersonList(); // 关键：继续抽奖时重新使用默认数据
  await enterLottery();
};

const quitLottery = () => {
  enterLottery(); // 进入抽奖时会自动加载默认数据
  currentStatus.value = 0;
};

const confettiFire = () => {
  const duration = 3 * 1000;
  const end = Date.now() + duration;
  (function frame() {
    confetti({ particleCount: 2, angle: 60, spread: 55, origin: { x: 0 } });
    confetti({ particleCount: 2, angle: 120, spread: 55, origin: { x: 1 } });
    if (Date.now() < end) requestAnimationFrame(frame);
  })();
  centerFire(0.25, { spread: 26, startVelocity: 55 });
  centerFire(0.2, { spread: 60 });
  centerFire(0.35, { spread: 100, decay: 0.91, scalar: 0.8 });
  centerFire(0.1, { spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 });
  centerFire(0.1, { spread: 120, startVelocity: 45 });
};

const centerFire = (particleRatio: number, opts: any) => {
  const count = 200;
  confetti({
    origin: { y: 0.7 },
    ...opts,
    particleCount: Math.floor(count * particleRatio),
  });
};

const randomBallData = (mod: "default" | "lucky" | "sphere" = "default") => {
  intervalTimer.value = setInterval(() => {
    const indexLength = 4;
    const cardRandomIndexArr: number[] = [];
    const personRandomIndexArr: number[] = [];
    for (let i = 0; i < indexLength; i++) {
      cardRandomIndexArr.push(
        Math.round(Math.random() * (tableData.value.length - 1))
      );
      personRandomIndexArr.push(
        Math.round(Math.random() * (allPersonList.value.length - 1))
      );
    }
    for (let i = 0; i < cardRandomIndexArr.length; i++) {
      if (!objects.value[cardRandomIndexArr[i]]) continue;
      objects.value[cardRandomIndexArr[i]].element = useElementStyle(
        objects.value[cardRandomIndexArr[i]].element,
        allPersonList.value[personRandomIndexArr[i]],
        cardRandomIndexArr[i],
        patternList.value,
        patternColor.value,
        cardColor.value,
        { width: cardSize.value.width, height: cardSize.value.height },
        textSize.value,
        mod
      );
    }
  }, 200);
};

const listenKeyboard = () => {
  window.addEventListener("keydown", (e: KeyboardEvent) => {
    if ((e.keyCode !== 32 && e.keyCode !== 27) || !canOperate.value) return;

    if (e.keyCode === 27 && currentStatus.value === 3) {
      quitLottery();
      return;
    }

    if (e.keyCode !== 32) return;

    switch (currentStatus.value) {
      case 0:
        enterLottery();
        break;
      case 1:
        startLottery();
        break;
      case 2:
        stopLottery();
        break;
      case 3:
        continueLottery();
        break;
    }
  });
};

onMounted(() => {
  // 初始加载默认数据
  setDefaultPersonList();
  animation();
  if (containerRef.value) {
    containerRef.value.style.color = textColor.value;
  }
  listenKeyboard();
});

onUnmounted(() => {
  clearInterval(intervalTimer.value);
  intervalTimer.value = null;
  window.removeEventListener("keydown", listenKeyboard);
  window.removeEventListener("resize", onWindowResize);
});
</script>

<template>
  <el-button class="backBtn" type="info" plain @click="router.push('/')"
    >返回选择</el-button
  >
  <div
    class="absolute z-10 flex flex-col items-center justify-center -translate-x-1/2 left-1/2"
  >
    <h2
      class="pt-12 m-0 mb-12 font-mono tracking-wide text-center leading-12 header-title"
      :style="{ fontSize: textSize * 1.5 + 'px', color: textColor }"
    >
      {{ topTitle }}
    </h2>
    <!-- 移除手动加载默认数据的按钮，因为已自动加载 -->
  </div>
  <div id="container" ref="containerRef" class="3dContainer">
    <div id="menu">
      <button
        class="btn-end"
        @click="enterLottery"
        v-if="currentStatus == 0 && tableData.length > 0"
      >
        进入抽奖
      </button>

      <div class="start" v-if="currentStatus == 1">
        <button class="btn-start" @click="startLottery">
          <strong>开始抽取 </strong>
          <div id="container-stars">
            <div id="stars"></div>
          </div>
          <div id="glow">
            <div class="circle"></div>
            <div class="circle"></div>
          </div>
        </button>
      </div>

      <button
        class="btn-end btn glass btn-lg"
        @click="stopLottery"
        v-if="currentStatus == 2"
      >
        停止
      </button>

      <div v-if="currentStatus == 3" class="flex justify-center gap-6 enStop">
        <div class="start">
          <button class="btn-start" @click="continueLottery">
            <strong>继续抽取</strong>
            <div id="container-stars">
              <div id="stars"></div>
            </div>
            <div id="glow">
              <div class="circle"></div>
              <div class="circle"></div>
            </div>
          </button>
        </div>
        <div class="start">
          <button class="btn-cancel" @click="quitLottery">
            <strong>退出</strong>
            <div id="container-stars">
              <div id="stars"></div>
            </div>
            <div id="glow">
              <div class="circle"></div>
              <div class="circle"></div>
            </div>
          </button>
        </div>
      </div>
    </div>
  </div>
  <StarsBackground></StarsBackground>
  <PrizeList class="absolute left-0 top-32"></PrizeList>
</template>

<style scoped lang="scss">
/* 样式保持不变 */
.backBtn {
  cursor: pointer;
  position: absolute;
  left: 8px;
  z-index: 9999;
  top: 8px;
}
#menu {
  position: absolute;
  z-index: 100;
  width: 100%;
  bottom: 50px;
  text-align: center;
  margin: 0 auto;
  font-size: 32px;
}

.header-title {
  -webkit-animation: tracking-in-expand-fwd 0.8s
    cubic-bezier(0.215, 0.61, 0.355, 1) both;
  animation: tracking-in-expand-fwd 0.8s cubic-bezier(0.215, 0.61, 0.355, 1)
    both;
}

.start {
  display: flex;
  justify-content: center;
}

.btn-start {
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 13rem;
  overflow: hidden;
  height: 3rem;
  background-size: 300% 300%;
  backdrop-filter: blur(1rem);
  border-radius: 5rem;
  transition: 0.5s;
  animation: gradient_301 5s ease infinite;
  border: double 4px transparent;
  background-image: linear-gradient(#212121, #212121),
    linear-gradient(
      137.48deg,
      #ffdb3b 10%,
      #fe53bb 45%,
      #8f51ea 67%,
      #0044ff 87%
    );
  background-origin: border-box;
  background-clip: content-box, border-box;
  -webkit-animation: pulsate-fwd 1.2s ease-in-out infinite both;
  animation: pulsate-fwd 1.2s ease-in-out infinite both;
}

.btn-cancel {
  cursor: pointer;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 13rem;
  overflow: hidden;
  height: 3rem;
  background-size: 300% 300%;
  backdrop-filter: blur(1rem);
  border-radius: 5rem;
  transition: 0.5s;
  animation: gradient_301 5s ease infinite;
  border: double 4px transparent;
  background-image: linear-gradient(#212121, #212121),
    linear-gradient(
      137.48deg,
      #ffdb3b 10%,
      #fe53bb 45%,
      #8f51ea 67%,
      #0044ff 87%
    );
  background-origin: border-box;
  background-clip: content-box, border-box;
}

#container-stars {
  position: absolute;
  z-index: -1;
  width: 100%;
  height: 100%;
  overflow: hidden;
  transition: 0.5s;
  backdrop-filter: blur(1rem);
  border-radius: 5rem;
}

strong {
  z-index: 2;
  font-family: "Avalors Personal Use";
  font-size: 12px;
  letter-spacing: 5px;
  color: #ffffff;
  text-shadow: 0 0 4px white;
}

#glow {
  position: absolute;
  display: flex;
  width: 12rem;
}

.circle {
  width: 100%;
  height: 30px;
  filter: blur(2rem);
  animation: pulse_3011 4s infinite;
  z-index: -1;
}

.circle:nth-of-type(1) {
  background: rgba(254, 83, 186, 0.636);
}

.circle:nth-of-type(2) {
  background: rgba(142, 81, 234, 0.704);
}

.btn-start:hover #container-stars {
  z-index: 1;
  background-color: #212121;
}

.btn-start:hover {
  transform: scale(1.1);
}

.btn-start:active {
  border: double 4px #fe53bb;
  background-origin: border-box;
  background-clip: content-box, border-box;
  animation: none;
}

.btn-start:active .circle {
  background: #fe53bb;
}

#stars {
  position: relative;
  background: transparent;
  width: 200rem;
  height: 200rem;
}

#stars::after {
  content: "";
  position: absolute;
  top: -10rem;
  left: -100rem;
  width: 100%;
  height: 100%;
  animation: animStarRotate 90s linear infinite;
}

#stars::after {
  background-image: radial-gradient(#ffffff 1px, transparent 1%);
  background-size: 50px 50px;
}

#stars::before {
  content: "";
  position: absolute;
  top: 0;
  left: -50%;
  width: 170%;
  height: 500%;
  animation: animStar 60s linear infinite;
}

#stars::before {
  background-image: radial-gradient(#ffffff 1px, transparent 1%);
  background-size: 50px 50px;
  opacity: 0.5;
}

@keyframes animStar {
  from {
    transform: translateY(0);
  }

  to {
    transform: translateY(-135rem);
  }
}

@keyframes animStarRotate {
  from {
    transform: rotate(360deg);
  }

  to {
    transform: rotate(0);
  }
}

@keyframes gradient_301 {
  0% {
    background-position: 0% 50%;
  }

  50% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0% 50%;
  }
}

@keyframes pulse_3011 {
  0% {
    transform: scale(0.75);
    box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.7);
  }

  70% {
    transform: scale(1);
    box-shadow: 0 0 0 10px rgba(0, 0, 0, 0);
  }

  100% {
    transform: scale(0.75);
    box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
  }
}

.btn-end {
  -webkit-animation: pulsate-fwd 0.9s ease-in-out infinite both;
  animation: pulsate-fwd 0.9s ease-in-out infinite both;
  cursor: pointer;
}

.btn-end {
  --glow-color: rgb(217, 176, 255);
  --glow-spread-color: rgba(191, 123, 255, 0.781);
  --enhanced-glow-color: rgb(231, 206, 255);
  --btn-color: rgb(100, 61, 136);
  border: 0.25em solid var(--glow-color);
  padding: 1em 3em;
  color: var(--glow-color);
  font-size: 15px;
  font-weight: bold;
  background-color: var(--btn-color);
  border-radius: 1em;
  outline: none;
  box-shadow: 0 0 1em 0.25em var(--glow-color),
    0 0 4em 1em var(--glow-spread-color),
    inset 0 0 0.75em 0.25em var(--glow-color);
  text-shadow: 0 0 0.5em var(--glow-color);
  position: relative;
  transition: all 0.3s;
  -webkit-animation: swing-in-top-fwd 0.5s
    cubic-bezier(0.175, 0.885, 0.32, 1.275) both;
  animation: swing-in-top-fwd 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) both;
}

.btn-end::after {
  pointer-events: none;
  content: "";
  position: absolute;
  top: 120%;
  left: 0;
  height: 100%;
  width: 100%;
  background-color: var(--glow-spread-color);
  filter: blur(2em);
  opacity: 0.7;
  transform: perspective(1.5em) rotateX(35deg) scale(1, 0.6);
}

.btn-end:hover {
  color: var(--btn-color);
  background-color: var(--glow-color);
  box-shadow: 0 0 1em 0.25em var(--glow-color),
    0 0 4em 2em var(--glow-spread-color),
    inset 0 0 0.75em 0.25em var(--glow-color);
}

.btn-end:active {
  box-shadow: 0 0 0.6em 0.25em var(--glow-color),
    0 0 2.5em 2em var(--glow-spread-color),
    inset 0 0 0.5em 0.25em var(--glow-color);
}

@-webkit-keyframes pulsate-fwd {
  0% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }

  50% {
    -webkit-transform: scale(1.1);
    transform: scale(1.1);
  }

  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
}

@keyframes pulsate-fwd {
  0% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }

  50% {
    -webkit-transform: scale(1.2);
    transform: scale(1.2);
  }

  100% {
    -webkit-transform: scale(1);
    transform: scale(1);
  }
}

@-webkit-keyframes tracking-in-expand-fwd {
  0% {
    letter-spacing: -0.5em;
    -webkit-transform: translateZ(-700px);
    transform: translateZ(-700px);
    opacity: 0;
  }

  40% {
    opacity: 0.6;
  }

  100% {
    -webkit-transform: translateZ(0);
    transform: translateZ(0);
    opacity: 1;
  }
}

@keyframes tracking-in-expand-fwd {
  0% {
    letter-spacing: -0.5em;
    -webkit-transform: translateZ(-700px);
    transform: translateZ(-700px);
    opacity: 0;
  }

  40% {
    opacity: 0.6;
  }

  100% {
    -webkit-transform: translateZ(0);
    transform: translateZ(0);
    opacity: 1;
  }
}
</style>